Pour en finir avec ces erreurs
Julien Lenormand - Kaizen Solutions
39 slides (non-numérotées)
TODO: vocabulaire module/package
Julien Lenormand
Ingénieur informatique
Pythonista depuis ~2009
pythonmodule toto not foundAttributeError: module 'math' has no attribute 'pi'Les imports et donc le Path
Objectif : tout comprendre !
import totobuiltins.__import__The Python
langage reference, The import statement
import totototo et le
bind dans le module actuel__import__ + bindtoto = __import__("toto") (grosse généralisation). . .
import toto as tata c’est
tata = __import__("toto")as sert juste à binder sur un nom
différent (pratique !)import numpy as np__import__importlib.import_moduleimportlib — The implementation of
import
def import_module(name, package=None):
"""An approximate implementation of import."""
absolute_name = importlib.util.resolve_name(name, package)
try:
return sys.modules[absolute_name]
except KeyError:
pass
path = None
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
break
else:
msg = f'No module named {absolute_name!r}'
raise ModuleNotFoundError(msg, name=absolute_name)
module = importlib.util.module_from_spec(spec)
sys.modules[absolute_name] = module
spec.loader.exec_module(module)
if path is not None:
setattr(parent_module, child_name, module)
return modulePEP 328 – Imports: Multi-Line and Absolute/Relative (2004)
from .titi import tututoto/tata.py qui fait
from ..titi import tutuimport titi.tutusys.modules
si "toto" est présent
sys.meta_path
finders, qui ne se basent pas sur le sys.pathsys.path_hooks
finders qui se basent sur le sys.pathModuleNotFoundErrorInterface :
>>> sys.builtin_module_names
('_abc', '_ast', '_codecs', '_collections', '_functools', '_imp', '_io',
'_locale', '_operator', '_signal', '_sre', '_stat', '_string', '_symtable',
'_thread', '_tracemalloc', '_warnings', '_weakref', 'atexit', 'builtins',
'errno', 'faulthandler', 'gc', 'itertools', 'marshal', 'posix', 'pwd', 'sys',
'time', 'xxsubtype')
```
frozen importlib._bootstrap par exemple, qui ne contient
que des imports builtin, et implémente le core de la fonctionnalité
d’import de Pythoncpython/Lib/importlib/_bootstrap_external.pycpython/Tools/build/freeze_modules.pycpython/Python/frozen_modules/README.txtPython/importlib.h
(2017)cpython/Makefile.pre.inInterface :
toto.__spec__ >>> import sys
>>> sys.__spec__
ModuleSpec(name='sys',
loader=<class '_frozen_importlib.BuiltinImporter'>,
origin='built-in')`
>>> import toto.tutu
>>> toto.tutu.__spec__
ModuleSpec(name='toto.tutu',
loader=<_frozen_importlib_external.SourceFileLoader object at 0x00000225EF0ABD10>
origin='/data/talk-import/toto/tutu.py')ModuleTypeLoader.create_module
: create_module(spec) -> Optional[ModuleType]__name__,
__package__,
__spec__,__path__
et __file__
optionnels,sys.modules (avant
son init, pour permettre les imports circulaires)__init__ si ce n’est
pas un namespace
package : Loader.exec_module(module)
: exec_module(module) -> None
sys.modules et re-raise l’erreurObjects that implement both of these interfaces are referred to as importers - they return themselves when they find that they can load the requested module.
BuiltinImporterFrozenImporterzipimporterdef import_module(name, package=None):
"""An approximate implementation of import."""
absolute_name = importlib.util.resolve_name(name, package)
try:
return sys.modules[absolute_name]
except KeyError:
pass
path = None
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
break
else:
msg = f'No module named {absolute_name!r}'
raise ModuleNotFoundError(msg, name=absolute_name)
module = importlib.util.module_from_spec(spec)
sys.modules[absolute_name] = module
spec.loader.exec_module(module)
if path is not None:
setattr(parent_module, child_name, module)
return moduleNon.
__init__ d’un package
?__init__.py d’un package__all__
import toto qui
importe tout ce qui est pertinent, plutôt que de devoir chasser dans les
subpackagessys.pathsys.path module search path :
python path/to/file.py -> /abs/path/to/python -m path.to.file ->
/abs/PYTHONPATH
si défini/usr/lib/python38.zip (dans un fichier
zip !)/usr/lib/python3.8/site-packages/home/talk/python-import/venv/lib/site-packagessite,
pyvenv.cfg, PYTHONHOME,
virtual environments, _pth
filessys.path_importer_cachesys.path
(une liste) : append/prependpythonmodule toto not foundAttributeError: module 'math' has no attribute 'pi'sys.path et comparer par
rapport à où est installé le modulesys.pathPYTHONPATH pour contenir la
racine des sources du projetsys.path.(ap/pre)pend--system-site-packages)py
et les venvimportlib.reload
sauf TRES bonne raisonsys.path et
sys.modules pour debugimport this
import antigravityfrom __future__ import bracessys.pathLes 4 piliers des problèmes d’import :
importlib?
Julien Lenormand
Dev et responsable du Pôle Software
julien.lenormand@kaizen-solutions.net
Comment comprendre ?